﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
using Microsoft.WVB.Framework;
using Microsoft.WVB.Silverlight.Infrastructure;

namespace Microsoft.WVB.UI
{
    [TemplatePart(Name = WindowContainer.CaptureElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = WindowContainer.ResizeElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = WindowContainer.MinimizeElement, Type = typeof(Button))]
    [TemplatePart(Name = WindowContainer.ClosingElement, Type = typeof(Button))]
    [TemplatePart(Name = WindowContainer.HeaderElement, Type = typeof(ContentControl))]
    [TemplatePart(Name = WindowContainer.WindowHeaderElement, Type = typeof(FrameworkElement))]
    [TemplateVisualState(Name = VisualStates.StateMouseOver, GroupName = VisualStates.GroupCommon),
    TemplateVisualState(Name = VisualStates.StateNormal, GroupName = VisualStates.GroupCommon)]
    [ContentProperty("Content")]
    public class WindowContainer : ContentControl, IDisposable, IManagedControl
    {
        private FrameworkElement _captureElement;
        private FrameworkElement _resizeElement;
        private Button _closingElement, _minimizeElement;
        private FrameworkElement _windowHeader;
        private double beginX, beginY;
        private bool isDragging;
        private bool isResizing;
        private Size normalSize = Size.Empty;
        private IPlayerModel PlayModel { get; set; }
        private const string CaptureElement = "CaptureElement";
        private const string ResizeElement = "ResizeElement";
        private const string ClosingElement = "ClosingElement";
        private const string MinimizeElement = "CloseElement";
        private const string HeaderElement = "HeaderElement";
        private const string WindowHeaderElement = "WindowBar";

        internal ContentControl ElementHeader { get; set; }

        // Commented out in favour of using the Application global property PL. May revisit

        ////public Boolean FullScreen
        ////{
        ////    get { return (Boolean)GetValue(FullScreenProperty); }
        ////    set { SetValue(FullScreenProperty, value); }
        ////}
    
        ////public static readonly DependencyProperty FullScreenProperty = null;

        public Object HeaderContent
        {
            get { return (Object)GetValue(HeaderContentProperty); }
            set { SetValue(HeaderContentProperty, value); }
        }
        public static readonly DependencyProperty HeaderContentProperty;

        public DataTemplate HeaderTemplate
        {
            get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
            set { SetValue(HeaderTemplateProperty, value); }
        }
        public static readonly DependencyProperty HeaderTemplateProperty = null;

        /// <summary>
        /// Is the Window resizeable
        /// </summary>
        public bool Resizeable
        {
            get
            {
                return (bool)GetValue(ResizeableProperty); 
            }

            set
            {
                SetValue(ResizeableProperty, value);
            }
        }
        public static readonly DependencyProperty ResizeableProperty = null;

        /// <summary>
        /// Show Window Header
        /// </summary>
        public bool ShowWindowHeader
        {
            get
            {
                return (bool)GetValue(ShowWindowHeaderProperty);
            }

            set
            {
                SetValue(ShowWindowHeaderProperty, value);
            }
        }
        public static readonly DependencyProperty ShowWindowHeaderProperty = null;

        static WindowContainer()
        {
            HeaderContentProperty = DependencyProperty.Register("HeaderContent", typeof(Object), typeof(WindowContainer), new PropertyMetadata(new PropertyChangedCallback(OnHeaderChanged)));
            HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(WindowContainer), new PropertyMetadata(new PropertyChangedCallback(OnHeaderTemplateChanged)));
            ResizeableProperty = DependencyProperty.Register("Resizeable", typeof(bool), typeof(WindowContainer), new PropertyMetadata(false));

            ShowWindowHeaderProperty = DependencyProperty.Register("ShowWindowHeader", typeof(bool), typeof(WindowContainer), new PropertyMetadata(true));
            IsMouseOverProperty = DependencyProperty.Register("IsMouseOver", typeof(Boolean), typeof(WindowContainer), new PropertyMetadata(false));

            // See previous not about FullScreen property
            ////FullScreenProperty = DependencyProperty.Register("FullScreen", typeof(Boolean), typeof(WindowContainer), new PropertyMetadata(new PropertyChangedCallback(OnFullScreenChanged)));
        }

        ////private static void OnFullScreenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        ////{
        ////    if ((bool)e.NewValue)
        ////    {
        ////        ((WindowContainer)d).OnFullScreenEnter();
        ////    }
        ////    else
        ////    {
        ////        ((WindowContainer)d).OnFullScreenLeave();
        ////    }
        ////}

        private static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WindowContainer)d).OnHeaderChanged(e.OldValue, e.NewValue);
        }

        private static void OnHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WindowContainer)d).OnHeaderTemplateChanged((DataTemplate)e.OldValue, (DataTemplate)e.NewValue);
        }

        public virtual void OnFullScreenEnter()
        {
            if (this._captureElement != null)
            {
                //this._captureElement.Visibility = Visibility.Collapsed;
            }
        }

        public virtual void OnFullScreenLeave()
        {
            if (this._captureElement != null)
            {
                //this._captureElement.Visibility = Visibility.Visible;
            }
        }

        protected virtual void OnHeaderTemplateChanged(DataTemplate oldHeaderTemplate, DataTemplate newHeaderTemplate)
        {
            if (this.ElementHeader != null)
            {
                if (newHeaderTemplate == null)
                {
                    this.ElementHeader.Content = this.HeaderContent;
                }
                else
                {
                    FrameworkElement element = this.HeaderTemplate.LoadContent() as FrameworkElement;
                    this.ElementHeader.Content = element;
                }
            }
        }

        protected virtual void OnHeaderChanged(object oldHeader, object newHeader)
        {
            if ((HeaderTemplate == null) && (this.ElementHeader != null))
            {
                this.ElementHeader.Content = newHeader;
            }
        }

        public WindowContainer()
            : base()
        {
            this.DefaultStyleKey = typeof(WindowContainer);

            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {
                ////Binding fullScreenBinding = new Binding("IsFullScreen");
                ////fullScreenBinding.Source = Application.Current.Host.Content;
                ////fullScreenBinding.Mode = BindingMode.OneWay;
                ////this.SetBinding(FullScreenProperty, fullScreenBinding);

                this.Loaded += WindowContainer_Loaded;
             }
        }

        protected override void OnMouseEnter(MouseEventArgs e)
        {
            base.OnMouseEnter(e);
            this.IsMouseOver = true;
            UpdateVisualState();
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);
            this.IsMouseOver = false;
            UpdateVisualState();
        }

        private void WindowContainer_Loaded(object sender, RoutedEventArgs e)
        {
            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {
                IoC.GetCreate<ILayoutManager>().RegisterControl(this);
                this.Loaded -= WindowContainer_Loaded;

                // Hook system-wide FullScreen event
                Application.Current.Host.Content.FullScreenChanged += new EventHandler(Content_FullScreenChanged);
            }
        }

        private void Content_FullScreenChanged(object sender, EventArgs e)
        {
            if (Application.Current.Host.Content.IsFullScreen)
            {
                this.OnFullScreenEnter();
            }
            else
            {
                this.OnFullScreenLeave();
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            ElementHeader = base.GetTemplateChild(WindowContainer.HeaderElement) as ContentControl;
            _captureElement = base.GetTemplateChild(WindowContainer.CaptureElement) as FrameworkElement;
            _resizeElement = base.GetTemplateChild(WindowContainer.ResizeElement) as FrameworkElement;
            _closingElement = base.GetTemplateChild(WindowContainer.ClosingElement) as Button;
            _minimizeElement = base.GetTemplateChild(WindowContainer.MinimizeElement) as Button;
            _windowHeader = base.GetTemplateChild(WindowContainer.WindowHeaderElement) as FrameworkElement;
            
            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {
                if (_captureElement != null)
                {
                    _captureElement.MouseLeftButtonDown += captureElement_MouseLeftButtonDown;
                    _captureElement.MouseLeftButtonUp += captureElement_MouseLeftButtonUp;
                    _captureElement.MouseMove += captureElement_MouseMove;
                }

                if (_resizeElement != null)
                {
                    if (this.Resizeable == true)
                    {
                        this._resizeElement.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        this._resizeElement.Visibility = Visibility.Collapsed;
                    }

                    _resizeElement.MouseLeftButtonDown += resizeElement_MouseLeftButtonDown;
                    _resizeElement.MouseLeftButtonUp += new MouseButtonEventHandler(resizeElement_MouseLeftButtonUp);
                    _resizeElement.MouseMove += new MouseEventHandler(resizeElement_MouseMove);
                }
            
                if (_closingElement != null)
                {
                    _closingElement.Click += new RoutedEventHandler(closingElement_Click);
                }

                if (null != _minimizeElement)
                {
                    _minimizeElement.Click += new RoutedEventHandler(minimizeElement_Click);
                }

                if (this.ShowWindowHeader == false)
                {
                    this._windowHeader.Visibility = Visibility.Collapsed;
                    this._resizeElement.Visibility = Visibility.Collapsed;
                }

                this.MouseLeftButtonUp += new MouseButtonEventHandler(ViewContainer_MouseLeftButtonUp);
            }

            this.ChangeVisualState(false);
        }

        #region Resize
        static double MinWindowWidth = 100.0;
        static double MinWindowHeight = 100.0;
        void resizeElement_MouseMove(object sender, MouseEventArgs e)
        {
            if (isResizing)
            {
                double curX = e.GetPosition(null).X;
                double curY = e.GetPosition(null).Y;
                double dX = curX - beginX;
                double dY = curY - beginY;
                double newWidth = this.ActualWidth + dX;
                double newHeight = this.ActualHeight + dY;
                this.Width = newWidth > MinWindowWidth ? newWidth : MinWindowWidth;
                this.Height = newHeight > MinWindowHeight ? newHeight : MinWindowHeight;
                beginX = curX;
                beginY = curY;
            }
        }
        void resizeElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            beginX = e.GetPosition(null).X;
            beginY = e.GetPosition(null).Y;
            _resizeElement.CaptureMouse();
            this.Opacity = 0.5;
            isResizing = true;
        }
        void resizeElement_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!isResizing)
            {
                if (null != Activated)
                    Activated(this, null);
            }
            _resizeElement.ReleaseMouseCapture();
            this.Opacity = 1;
            isResizing = false;
        }
        #endregion

        void ViewContainer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!isDragging)
            {
                if (null != Activated)
                    Activated(this, null);
            }
        }

        void minimizeElement_Click(object sender, RoutedEventArgs e)
        {
            //Send message to windows manager TODO
            this.Visibility = Visibility.Collapsed;
            if (null != Minimize)
            {
                Minimize(this, null);
            }
        }

        internal virtual void ChangeVisualState(bool useTransitions)
        {
            if (this.IsMouseOver)
            {
                VisualStates.GoToState(this, useTransitions, new String[] { VisualStates.StateMouseOver });
            }
            else
            {
                VisualStates.GoToState(this, useTransitions, new String[] { VisualStates.StateNormal });
            }
        }

        internal void UpdateVisualState()
        {
            this.UpdateVisualState(true);
        }

        internal void UpdateVisualState(bool useTransitions)
        {
            this.ChangeVisualState(useTransitions);  
        }
        
        void closingElement_Click(object sender, RoutedEventArgs e)
        {
            this.Visibility = Visibility.Collapsed;
            // Send message to manager
            if (null != Close)
            {
                Close(this, null);
            }
        }

        #region Capture Element Mouse Event Handlers
        void captureElement_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDragging)
            {
                double curX = e.GetPosition(null).X;
                double curY = e.GetPosition(null).Y;
                double dX = curX - beginX;
                double dY = curY - beginY;
                this.SetValue(Canvas.LeftProperty, Canvas.GetLeft(this) + dX);
                this.SetValue(Canvas.TopProperty, Canvas.GetTop(this) + dY);
                beginX = curX;
                beginY = curY;
            }

        }

        void captureElement_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!isDragging)
            {
                if (null != Activated)
                    Activated(this, null);
            }
            _captureElement.ReleaseMouseCapture();
            this.Opacity = 1;
            isDragging = false;
        }

        void captureElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            beginX = e.GetPosition(null).X;
            beginY = e.GetPosition(null).Y;
            _captureElement.CaptureMouse();
            this.Opacity = 0.5;
            isDragging = true;
        }
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (_captureElement != null)
            {
                _captureElement.MouseLeftButtonDown -= captureElement_MouseLeftButtonDown;
                _captureElement.MouseLeftButtonUp -= captureElement_MouseLeftButtonUp;
                _captureElement.MouseMove -= captureElement_MouseMove;
            }
            if (_resizeElement != null)
            {
                _resizeElement.MouseLeftButtonDown -= resizeElement_MouseLeftButtonDown;
                _resizeElement.MouseLeftButtonUp -= resizeElement_MouseLeftButtonUp;
                _resizeElement.MouseMove -= resizeElement_MouseMove;
            }

            if (_closingElement != null)
            {
                _closingElement.Click -= closingElement_Click;
            }
            if (null != _minimizeElement)
            {
                _minimizeElement.Click -= minimizeElement_Click;
            }
        }

        #endregion

        #region IManagedControl Members

        public ContentControl Control
        {
            get { return this; }
        }

        public Size NormalSize
        {
            get
            { 
                return this.normalSize; 
            }
        }

        public event EventHandler Minimize;
        public event EventHandler Close;
        public event EventHandler Activated;

        public void StashNormalSize()
        {
            if (Double.IsNaN(this.Width) == false)
            {
                this.normalSize.Width = this.Width;
            }

            if (Double.IsNaN(this.Height) == false)
            {
                this.normalSize.Height = this.Height;
            }
        }

        #endregion

        public string LayoutGroup
        {
            get { return (string)GetValue(LayoutGroupProperty); }
            set { SetValue(LayoutGroupProperty, value); }
        }
        public static readonly DependencyProperty LayoutGroupProperty = DependencyProperty.Register("LayoutGroup", typeof(string), typeof(WindowContainer), null);

        public LayoutGroupMode LayoutMode
        {
            get { return (LayoutGroupMode)GetValue(LayoutModeProperty); }
            set { SetValue(LayoutModeProperty, value); }
        }
        public static readonly DependencyProperty LayoutModeProperty = DependencyProperty.Register("LayoutMode", typeof(LayoutGroupMode), typeof(WindowContainer), null);

        public Boolean IsMouseOver
        {
            get { return (Boolean)GetValue(IsMouseOverProperty); }
            set { SetValue(IsMouseOverProperty, value); }
        }
        public static readonly DependencyProperty IsMouseOverProperty = null;
    }
}
